<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <meta name="keywords" content="tvvm, TVVM, TV Web App framework, focus, keybind, vue" />
  <meta name="description" content="A simple micro-library for agile building TV web app with no dependency | 轻量级电视web应用开发框架" />
  <title>TVVM</title>
  <link rel="stylesheet" href="../style/common.css" />
  <link rel="stylesheet" href="../style/iconfont.css">
  <link rel="shortcut icon" href="../favicon.ico">
  <link rel="stylesheet" href="../style/mono-blue.css">
  <link rel="stylesheet" href="../style/doc.css">
  <script src="../scripts/bscroll.min.js"></script>
  <script src="../scripts/highlight.pack.js"></script>
  <script>hljs.initHighlightingOnLoad();</script>
  <script src="https://unpkg.com/tvvm/dist/tvvm.min.js"></script>
  <script src="../../dist/tvvm.js"></script>
</head>
<body>
  <div id="doc">
    <nav class="navbar">
      <div class="logo" >TVVM</div>
      <div class="menu-button" @click="methods.toggleMenu" @touchstart="methods.toggleMenu">
        <i id="menu-button" t-class="data.buttonClassList" class="iconfont icon-menu"></i>
        <span style="margin-left: 10px;">TVVM</span>
      </div>
      <div class="link-list">
        <a href="../index.html">Home</a>
        <span>/</span>
        <a style="font-weight: bold;">Doc</a>
        <span>/</span>
        <a href="https://github.com/zexiplus/TVVM">Github</a>
      </div>
    </nav>
    <div class="container">
      <div class="left-nav" t-class="data.navClassList">
        <div class="nav-list-wrapper"> 
          <span class="link-title">
            <a href="#start">开始</a>
          </span>
          <div class="link-group">
            <a href="#desc">介绍</a>
            <a href="#download">下载</a>
            <a href="#usage">使用</a>
          </div>
          <span class="link-title">
            <a href="#feature">特色</a>
          </span>
          <div class="link-group">
            <a href="#focus-control">焦点控制</a>
            <a href="#event-optmize">事件优化</a>
            <a href="#data-drive">数据驱动</a>
          </div>
          <span class="link-title">
            <a href="#api">API</a>
          </span>
          <div class="link-group">
            <a href="#instance">实例化</a>
            <a href="#directives">指令</a>
            <div class="link-detail">
              <a href="#t-index">t-index</a>
              <a href="#t-if">t-if</a>
              <a href="#t-for">t-for</a>
              <a href="#data-bind">data bind</a>
              <a href="#t-class">t-class</a>
              <a href="#t-bind">t-bind</a>
              <a href="#t-value">t-value</a>
              <a href="#event-bind">event bind</a>
            </div>
            <a href="#options">选项</a>
            <div class="link-detail">
              <a href="#el">el</a>
              <a href="#data">data</a>
              <a href="#focus">focus</a>
              <a href="#methods">methods</a>
              <a href="#hooks">hooks</a>
            </div>
          </div>
        </div>
      </div>

      <div class="content-wrapper">
        <div class="content">
        <h1 id="start">开始</h1>

        <h2 id="desc">介绍</h2>
        <span class="desc-text">
            TVVM是一个专门为TV WEB APP开发的MVVM模式框架， 它帮助开发者快速开发应用而无需关心焦点控制， 
            键盘绑定， 数据绑定等通用逻辑。
            它没有依赖， 体型小巧（20kb）
        </span>

        <h2 id="download">下载</h2>
        <h3>通过npm下载</h3>
        <span class="desc-text">你的系统上需要安装有nodejs</span>
        <pre>
          <code class="bash">$ npm install -S tvvm</code>
        </pre>

        <h3>手动下载</h3>
        <span class="desc-text">
          你也可以通过手动下载的方式， 然后通过&lt;script&gt;标签进行引用，
          <a href="https://unpkg.com/tvvm@1.0.2/dist/tvvm.min.js">下载链接</a>
        </span>

        <h2 id="usage">使用</h2>
        <pre>
          <code class="javascript">
  // es module
  import * as TVVM from 'tvvm'

  var tv = new TVVM({
  ...options
  })
          </code>
          <code class="html">
  &lt;!-- html --&gt;
  &lt;script src="https://unpkg.com/tvvm/dist/tvvm.min.js"&gt;&lt;/script&gt;
  &lt;script&gt;
      var tv = new TVVM({
        ...options
      })
  &lt;/script&gt;
          </code>
        </pre>

        <h1 id="feature">特色</h1>
        <h2 id="focus-control">焦点自动控制</h2>
        <span class="desc-text">
          <span>
            TV应用的特点是使用遥控器控制焦点移动， 而并非鼠标点击/手势触摸事件来触发控件， 从而进行下一步操作。
            这需要我们通过编程的方式控制焦点的移动和跳转。TVVM致力于减少焦点移动的代码逻辑， 通过配置t-index索引， 而非编程的方式解决焦点的移动。
          </span><br>
          <span style="text-indent: 2rem; display: block; margin-top: 10px;">
            TVVM把应用分成横轴空间和纵轴空间， 例如 声明 t-index="0-1" 代表应用是第1行 (row=0) 第2列 (col=1)为当前焦点 , 当你点击遥控器的向下移动按钮时 row 增加，col 不变， 此时焦点从 t-index="0-1"移动至 t-index="1-1"的元素上 。
            这些在TVVM内部已经做好了， 开发者只需要在焦点块元素上声明 t-index索引即可。
          </span>
          <span style="text-indent: 2rem; display: block; margin-top: 10px;">
            除此之外, TVVM还提供了丰富的选项， 例如默认焦点， 焦点元素样式， 边界穿越， 按键值配置等。
          </span>
        </span>
        <h4>focus选项</h4>
        <pre>
          <code class="javascript">
  new TVVM({
      ...,
      focus: {
        defaultFocusIndex: '0-1', // 默认焦点
        circle: {
          horizontal: true, // 当焦点移动到边界时在水平方向可穿越
          vertical: true // 当焦点移动到边界时在垂直方向可穿越
      },
          ...options
    }
  })
          </code>
          <code class="html">
  &lt;style&gt;
    *:focus {
        outline: none;
        border: 2px solid #fff;
    }
  &lt;/style&gt;
  &lt;div class=&quot;tv&quot;&gt;
      &lt;div&gt;
          &lt;div&gt;
              &lt;div t-index=&quot;0-1&quot;&gt;0-1&lt;/div&gt;
              &lt;div t-index=&quot;0-2&quot;&gt;0-2&lt;/div&gt;
              &lt;div t-index=&quot;0-3&quot;&gt;0-3&lt;/div&gt;
          &lt;/div&gt;
      &lt;/div&gt;
      &lt;div&gt;
          &lt;div t-index=&quot;1-0, 2-0&quot; real-focus=&quot;true&quot;&gt;
              &lt;span&gt;1-0,&lt;/span&gt; &lt;span&gt;2-0&lt;/span&gt;
          &lt;/div&gt;
          &lt;div&gt;
              &lt;div t-index=&quot;1-1, 1-2, 1-3&quot;&gt;
                  &lt;span&gt;1-1,&lt;/span&gt; &lt;span&gt;1-2,&lt;/span&gt; &lt;span&gt;1-3&lt;/span&gt;
              &lt;/div&gt;
              &lt;div&gt;
                  &lt;div t-index=&quot;2-1&quot;&gt;2-1&lt;/div&gt;
                  &lt;div t-index=&quot;2-2&quot;&gt;2-2&lt;/div&gt;
                  &lt;div t-index=&quot;2-3&quot;&gt;2-3&lt;/div&gt;
              &lt;/div&gt;
          &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;
          </code>
        </pre>
        <h4 style="margin-bottom: 1rem;">显示结果</h4>
        <img src="../imgs/index.bmp" alt="t-index">

        <h2 id="event-optmize">按键去抖优化</h2>
        <span class="desc-text">
            某些物理遥控器在按下按钮时， 有可能高速触发按键事件， 这对应用会产生不良后果， 
            TVVM在绑定事件的同时在内部会优化操作逻辑， 利用函数去抖控制按键触发频率， 防止因为物理设备差异导致应用逻辑混乱。
        </span>

        <h2 id="data-drive">数据驱动</h2>
        <span class="desc-text">
            TVVM与大多数mvvm思想的前端框架一样， 采用数据驱动的开发模式， 简单来讲，数据驱动使开发者只用关系数据的修改， 而无需手动将数据同步至视图。
            以下是 t-value 指令来实现双向数据绑定的例子， span标签内的内容会随着input输入框的值的改变而改变
        </span>
        <pre>
          <code class="javascript">
    data: function () {
        return {
            demoInputValue: 'demo'
        }
    }
          </code>
          <code class="html">
  &lt;input t-value=&quot;data.demoInputValue&quot; /&gt;
  &lt;span&gt;{{data.demoInputValue}}&lt;/span&gt;
          </code>
        </pre>
        <div class="demo-wrapper">
          <h4>demo</h4>
          <input t-value="data.demoInputValue" />
          <span>{{data.demoInputValue}}</span>
        </div>

        <h1 style="margin-top: 4rem;" id="api">API</h1>
        <h2 id="instance">实例化</h2>
          <span class="desc-text">new TVVM 返回一个tv实例, 作为该页面的全局单例入口</span>
          <pre>
            <code class="javascript">
  var tv = new TVVM({
    el: '#tv',
    data () {
        return {

        }
    },
    focus: {

    },
    methods: {
        testFn: function (a, b) {

        }
    }
  })
            </code>
          </pre>

          <h2 id="directives">指令</h2>
          <span class="desc-text">
            TVVM内置指令系统, 包含了一些常用的指令, 用于处理简单的模版逻辑.TVVM内置指令通常以 t- 开头作为标识
          </span>
          <pre>
            <code class="html">
  &lt;html&gt;
    &lt;head&gt;&lt;/head&gt;
    &lt;body&gt;
        &lt;div id=&quot;tv&quot;&gt;
            &lt;div t-if=&quot;data.dialogVisible&quot; class=&quot;dialog&quot;&gt;{{data.dialog.title}}&lt;/div&gt;
            &lt;nav&gt;
                &lt;a t-for=&quot;item in data.linkList&quot;&gt;{{item.label}}&lt;/a&gt;
            &lt;/nav&gt;
            &lt;form&gt;
              &lt;input t-value=&quot;data.dialog.title&quot; /&gt;
            &lt;/form&gt;
            &lt;div&gt;
            &lt;div &quot; t-index=&quot;1-1, 1-2, 1-3&quot;&gt;&lt;/div&gt;
            &lt;div&gt;
              &lt;div t-index=&quot;2-1&quot;&gt;&lt;/div&gt;
              &lt;div t-index=&quot;2-2&quot;&gt;&lt;/div&gt;
              &lt;div t-index=&quot;2-3&quot;&gt;&lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
    &lt;/body&gt;
  &lt;/html&gt;
            </code>
          </pre>
          <div class="block-content">
            <h3 id="t-index">t-index</h3>
            <div class="desc-text">
                用于指定焦点区块元素的二维空间位置索引，以便用户点击遥控器方向按键时移动焦点，t-index="x-y", 例如t-index="0-0"代表第一排第一列的元素
            </div>
            <pre>
              <code class="html">
 &lt;div class=&quot;tv&quot;&gt;
    &lt;div t-index=&quot;0-0&quot;&gt;0-0&lt;/div&gt; &lt;!-- 第1排第1个元素 --&gt;
    &lt;div t-index=&quot;0-1&quot;&gt;0-1&lt;/div&gt;
    &lt;div t-index=&quot;0-2&quot;&gt;0-2&lt;/div&gt;
    &lt;!-- 第2排第1个元素， 纵向占据2个空间 --&gt;
    &lt;div t-index=&quot;1-0, 2-0&quot;&gt;1-0， 2-0&lt;/div&gt; 
    &lt;div&gt;
        &lt;!-- 第2排第2个元素， 横向占据3个空间 --&gt;
        &lt;div t-index=&quot;1-1, 1-2, 1-3&quot;&gt;1-1， 1-2， 1-3&lt;/div&gt; 
        &lt;div&gt;
            &lt;div t-index=&quot;2-1&quot;&gt;2-1&lt;/div&gt; &lt;!-- 第3排第2个元素 --&gt;
            &lt;div t-index=&quot;2-2&quot;&gt;2-2&lt;/div&gt; &lt;!-- 第3排第3个元素 --&gt;
            &lt;div t-index=&quot;2-3&quot;&gt;2-3&lt;/div&gt; &lt;!-- 第3排第4个元素 --&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
              </code>
            </pre>
            <!-- <img src="../imgs/index.bmp" alt="t-index-demo"> -->
            <h3 id="t-if">t-if</h3>
            <span class="desc-text">
                用于显示/隐藏dom节点, 该指令接收一个在data参数上存在的布尔值
            </span>
            <pre>
              <code class="html">
&lt;div t-if=&quot;data.dialogVisible&quot;&gt;&lt;/div&gt;
              </code>
            </pre>
            <h3 id="t-for">t-for</h3>
            <span class="desc-text">
                用于循环指定的dom节点, 该指令接收一个表达式,如下item代表数组的每一项, array是data上定义的一个数组
            </span>
            <pre>
              <code class="html">
&lt;ul&gt;
  &lt;li t-for=&quot;item in data.array&quot;&gt;{{item.label}}&lt;/li&gt;
&lt;/ul&gt;
              </code>
            </pre>
            <h3 id="data-bind">data bind</h3>
            <span class="desc-text">
                数据插值, 双花括号({{}})内接收一个data的属性.用于页面内数据插值
            </span>
            <pre>
              <code class="javascript">
data: { name: 'float' }
              </code>
              <code class="html">
&lt;span&gt;{{data.name}}&lt;/span&gt;
&lt;!-- 渲染为 --&gt;
&lt;span&gt;float&lt;/span&gt;
              </code>
            </pre>

            <h3 id="t-class">t-class</h3>
            <span class="desc-text">
                样式表绑定， t-class接收一个data上已经定义的样式名数组或对象
            </span>
            <pre>
              <code class="javascript">
  data: function () {
      return {
          classList1: ['container', 'container-row'],
          classList2: {
              'container': true,
              'container-row': false,
              'container-col': true
          }
      }
  }
              </code>
              <code class="html">
  &lt;div t-class=&quot;data.classList2&quot;&gt;&lt;/div&gt;
  &lt;!-- 渲染为 --&gt;
  &lt;div class=&quot;container container-col&quot;&gt;&lt;/div&gt;
              </code>
            </pre>
            <h3 id="t-bind">t-bind</h3>
            <span class="desc-text">
              属性绑定,t-bind:name="data.name" 简写形式为 :name="data.name"
            </span>
            <pre>
              <code class="javascript">
  data: function () {
      return {
          id: 'billboard',
          height: '365',
          classname: 'spin'
      }
  }
              </code>
              <code class="html">
    &lt;div :id=&quot;data.id&quot; :height=&quot;data.height&quot; :class=&quot;data.classname&quot;&gt;&lt;/div&gt;
    &lt;!-- 渲染为 --&gt;
    &lt;div id=&quot;billboard&quot; height=&quot;365&quot; class=&quot;spin&quot;&gt;&lt;/div&gt;
              </code>
            </pre>

            <h3 id="t-value">t-value</h3>
            <span class="desc-text">
                用于input输入数据与data上数据的绑定， input的value会实时同步至t-model绑定的数据
            </span>
            <pre>
              <code class="javascript">
    data: function () {
        return {
            demoInputValue: 'demo'
        }
    }
              </code>
              <code class="html">
    &lt;input t-value=&quot;data.demoInputValue&quot; /&gt;
    &lt;span&gt;{{data.demoInputValue}}&lt;/span&gt;
              </code>
            </pre>
            <div class="demo-wrapper">
                <h4>demo</h4>
                <input t-value="data.demoInputValue" />
                <span>{{data.demoInputValue}}</span>
            </div>

            <h3 id="event-bind">event bind</h3>
            <span class="desc-text">
                事件绑定
            </span>
            <pre>
              <code class="javascript">
    methods: {
      clickHandler: function () {
          // do something
      },
      clickHandler2: function (param1, param2) {
              
      }
    }
              </code>
              <code class="html">
    &lt;div @click=&quot;methods.clickHandler&quot;&gt;&lt;/div&gt;
    &lt;div @click=&quot;methods.clickHandler2(data.inputValue)&quot;&gt;&lt;/div&gt;
              </code>
            </pre>
          </div>
          
          <h2 id="options">选项</h2>
          <span class="desc-text">
              new TVVM接收一个选项对象作为唯一参数
          </span>
          <pre>
            <code class="javascript">
var tv = new TVVM({
  el,
  data,
  focus,
  methods,
  lifeHooks,
})
            </code>
          </pre>
          <div class="block-content">
            <h3 id="el">el</h3>
            <span class="desc-text">
                new TVVM() 实例挂载的dom元素, 可以是一个元素查找符或者dom节点对象
            </span>
            <pre>
              <code class="javascript">
new TVVM({
    el: '#tv',
})
              </code>
            </pre>

            <h3 id="focus">focus</h3>
            <span class="desc-text">
              focus选项用于设置焦点移动， 键值绑定， 默认焦点等逻辑
            </span>
            <pre>
              <code class="javascript">
new TVVM({
  focus: {
    defaultFocusIndex: '1-0',
    keysMap: {
      'up': {
        codes: [38, 103],
        handler: function (event, node, index, prevNode) {

        }
      },
      'g': {
        codes: [71],
        handler: function (event, node, index, prevNode) {
          console.log('you press g')
        }
      },
    },
    keysMapMergeCoverage: false,
    circle: {
      horizontal: true,
      vertical: true,
    }
  }
})
              </code>
            </pre>

            <div class="block-indent-1">
              <h4 class="options-dot" id="defaultFocusIndex">defaultFocusIndex (可选)</h4>
              <span class="desc-text">
                  进入应用默认聚焦的元素的索引, 该参数为空时， 默认聚焦到页面首个焦点元素上
              </span>
              <pre>
                <code class="javascript">
    focus: {
        defaultIndex: '0-1'
    }
                </code>
              </pre>
              <h4 class="options-dot">activeClass (可选)</h4>
              <span class="desc-text">焦点元素的样式名</span>
              <pre>
                <code class="javascript">
    focus: {
      activeClass: 'high-light'
    }
                </code>
              </pre>

              <h4 class="options-dot" id="circle">circle (可选)</h4>
              <span class="desc-text">
                定义焦点在水平/垂直方向上是否可循环移动, 默认false. <br>
                - horizontal (可选) 焦点元素在水平方向是否可以循环移动, 默认false <br>
                - vertival (可选) 焦点元素在水平方向上是否可以循环移动, 默认false
                
              </span>
              <pre>
                <code class="javascript">
    focus: {
        circle: {
            horizontal: true,
            vertical: true
        }
    }
                </code>
              </pre>
  
              <h4 class="options-dot" id="keysMap">keysMap</h4>
              <span class="desc-text">
                  遥控器键盘键值码映射表,  该参数为空时使用默认键值码映射表<br>
                  - 'alias' 对应键值的别名<br>
                  - codes 对应键值数组<br>
                  - handler 对应按键值绑定的事件处理函数 参数分别是event(事件), node(当前焦点dom节点索引), index (当前焦点dom节点的t-index值), prevNode(上一个焦点dom节点索引)
              </span>
              <pre>
                <code class="javascript">
    focus: {
      keysMap: {
      'up': {
        codes: [38, 104],
        handler: function (event, node, index, prevNode)
      },
      'down': {
        codes: [40, 98],
        handler
      },
      'left': {
        codes: [37, 100],
        handler
      },
      'right': {
        codes: [39, 102],
        handler
      },
      'enter': {
        codes: [13, 32],
        handler
      }
    }
  
                </code>
              </pre>
              <h4 class="options-dot">keysMapMergeCoverage (可选)</h4>
              <span class="desc-text">
                  键值映射表合并策略true为覆盖, false为合并
              </span>
              <pre>
                <code class="javascript">
  focus: {
    keysMapMergeCoverage: false,
  }
                </code>
              </pre>
            </div>
            <h3 id="data">data</h3>
            <span class="desc-text">
                tv单例的数据对象, 可以是一个函数或者对象, 当该参数为函数时, 取值为该函数的返回值
            </span>
            <pre>
              <code class="javascript">
  new TVVM({
    data: function () {
        return {
            title: 'tvvm demo page',
            index: '0'
        }
    }
  })
              </code>
            </pre>
            <h3 id="methods">methods</h3>
            <span class="desc-text">
                该参数是一个对象, 存放所有的方法函数
            </span>
            <pre>
              <code class="javascript">
  methods: {
    methods1: function () {
        console.log('methods1')
    }
  }
              </code>
            </pre>
            <h3 id="hooks">hooks</h3>
            <span class="desc-text">
                生命周期钩子函数集合
            </span>
            <span>
              - beforeCreate
                在实例化之前调用， 此时不可访问data<br>
              - created
                在实例化后调用，此时data已经设置响应式， 并可访问<br>
              - beforeMount
                在实例被挂在到真实dom前调用<br>
              - mounted
                在实例被挂在到dom上时调用<br>
              - beforeUpdate
                响应式data变动从而导致视图更新前调用<br>
              - updated
                响应式data变动从而导致视图更新后调用<br>
              - beforeDestory
                在实例被销毁前调用<br>
            </span>
            <pre>
              <code class="javascript">
    hooks: {
      beforeCreate: function () {
          // this 指向tv实例
      },
      mounted: function () {
                
      },
      ...
    }
              </code>
            </pre>
          </div>
        </div>
      </div>


    </div>
    <div class="cloak cloak-hidden" t-class="data.cloakClassList" @click="methods.toggleMenu" @touchstart="methods.toggleMenu"></div>
    <footer class="footbar">

    </footer>
  </div>
  <script src="../scripts/doc.js"></script>
</body>
</html>